#pragma once
#ifndef MITRIGGER_H_
#define MITRIGGER_H_
#include <fstream>
#include <iostream>
#include <map>
#include <vector>
#include <math.h>
#include <time.h>
#include <assert.h>
#include <stdlib.h>
#include <iomanip>
#include <utility>
#include "htable.h"
#include "dictionary.h"
using namespace std;

#define DICTIONARY_LOAD_FACTOR  2.0

#ifndef GROWTH_STEP
#define GROWTH_STEP 1.5
#endif

const double neg_inf = log(0.0);
//const double pos_inf = -neg_inf;

class strstack;

struct dict_entry_mi {
	unsigned int *wCode;
	unsigned int code;
	unsigned long long first;
	unsigned long long second;
};

struct trigger_entry {
	unsigned int *wCode;
	unsigned int code;
	map<unsigned int*, unsigned long long> *triggeredTable;
};

struct trigger_entry_load {
	unsigned int *wCode;
	unsigned int code;
	map <unsigned int*, pair<double, double> > *triggeredTable;
};

class mitrigger
{
private:
	dictionary *dict;

	trigger_entry *triggerTable; // !< number of trigger
	htable<unsigned int*> *htbTrigger;
	unsigned int totalTrigger;
	unsigned int limSizeTrigger;

	dict_entry_mi *dictTable; //!< number of dict entry
	htable<unsigned int*> *htbDict;
	unsigned int totalSoloToken;
	unsigned int limSizeDict;

	// ---
	trigger_entry_load *triggerTableLoad;
	htable<unsigned int*> *htbTriggerLoad;
	unsigned int totalTriggerLoad;
	unsigned int limSizeTriggerLoad;
	// ---

	unsigned long long totalSoloCount; //!< Count of all tokens observed.
	unsigned long long totalPairCount; //!< Count of all word pairs observed, with distance.

	int offset;
	int maxWindowSize;
public:
	mitrigger(void);
	mitrigger(const string &inputFilename, dictionary &dict, int offset=3, int maxWindowSize=20);
	~mitrigger(void);

	// Returns log(exp(lx) + exp(ly)).
	double logAdd(const double lx, const double ly);
	// Returns log(exp(lx) - exp(ly)).
	double logSubtract(const double lx, const double ly);

	void tokenize(const string& str, const char& delimiter, vector<string>& tokens);

	void growTriggerTable();
	void growDictTable();
	void growTriggerTableLoad();

	inline unsigned int size();
	
	void generate(const string &inputFilename);

	void load(const string &inputFilename);

	void compMI(const string &outputFilename, double min_mi, int min_pair_count);

	double scoreMI(const string &trigger, const string &triggered);
	double scoreMI(const char *trigger, const char *triggered);
	double scorePMI(const string &trigger, const string &triggered);
	double scorePMI(const char *trigger, const char *triggered);

	double GetPMIValue(const string &context, const string &word, int N);
	double GetLanguageCost(const string& words, int N);
	double GetPhraseProb(const string &phrase, const int &N);

	void stat(const string &outputFilename);

};

#endif